// Decompiled by DJ v3.11.11.95 Copyright 2009 Atanas Neshkov  Date: 1/5/2011 14:17:47
// Home Page: http://members.fortunecity.com/neshkov/dj.html  http://www.neshkov.com/dj.html - Check often for new version!
// Decompiler options: packimports(3) 
// Source File Name:   TextBlock.java

package freemarker.core;

import java.io.IOException;

// Referenced classes of package freemarker.core:
//            TemplateElement, TrimInstruction, Macro, Assignment, 
//            AssignmentInstruction, PropertySetting, LibraryLoad, Comment, 
//            Environment

public final class TextBlock extends TemplateElement {

	public TextBlock(String text) {
		this(text, false);
	}

	public TextBlock(String text, boolean unparsed) {
		this(text.toCharArray(), unparsed);
	}

	private TextBlock(char text[], boolean unparsed) {
		this.text = text;
		this.unparsed = unparsed;
	}

	public void accept(Environment env) throws IOException {
		env.getOut().write(text);
	}

	public String getCanonicalForm() {
		String text = new String(this.text);
		if (unparsed)
			return "<#noparse>" + text + "</#noparse>";
		else
			return text;
	}

	public String getDescription() {
		String s = (new String(text)).trim();
		if (s.length() == 0)
			return "whitespace";
		if (s.length() > 20) {
			s = s.substring(0, 20) + "...";
			s = s.replace('\n', ' ');
			s = s.replace('\r', ' ');
		}
		return "text block (" + s + ")";
	}

	TemplateElement postParseCleanup(boolean stripWhitespace) {
		if (text.length == 0)
			return this;
		int openingCharsToStrip = 0;
		int trailingCharsToStrip = 0;
		boolean deliberateLeftTrim = deliberateLeftTrim();
		boolean deliberateRightTrim = deliberateRightTrim();
		if (!stripWhitespace || text.length == 0)
			return this;
		if (parent.parent == null && previousSibling() == null)
			return this;
		if (!deliberateLeftTrim)
			trailingCharsToStrip = trailingCharsToStrip();
		if (!deliberateRightTrim)
			openingCharsToStrip = openingCharsToStrip();
		if (openingCharsToStrip == 0 && trailingCharsToStrip == 0)
			return this;
		text = substring(text, openingCharsToStrip, text.length
				- trailingCharsToStrip);
		if (openingCharsToStrip > 0) {
			beginLine++;
			beginColumn = 1;
		}
		if (trailingCharsToStrip > 0)
			endColumn = 0;
		return this;
	}

	private boolean deliberateLeftTrim() {
		boolean result = false;
		for (TemplateElement elem = nextTerminalNode(); elem != null
				&& elem.beginLine == endLine; elem = elem.nextTerminalNode()) {
			if (!(elem instanceof TrimInstruction))
				continue;
			TrimInstruction ti = (TrimInstruction) elem;
			if (!ti.left && !ti.right)
				result = true;
			if (!ti.left)
				continue;
			result = true;
			int lastNewLineIndex = lastNewLineIndex();
			if (lastNewLineIndex < 0 && beginColumn != 1)
				continue;
			char firstPart[] = substring(text, 0, lastNewLineIndex + 1);
			char lastLine[] = substring(text, 1 + lastNewLineIndex);
			if (trim(lastLine).length == 0) {
				text = firstPart;
				endColumn = 0;
				continue;
			}
			int i;
			for (i = 0; Character.isWhitespace(lastLine[i]); i++)
				;
			char printablePart[] = substring(lastLine, i);
			text = concat(firstPart, printablePart);
		}

		if (!result)
			;
		return result;
	}

	private boolean deliberateRightTrim() {
		boolean result = false;
		for (TemplateElement elem = prevTerminalNode(); elem != null
				&& elem.endLine == beginLine; elem = elem.prevTerminalNode()) {
			if (!(elem instanceof TrimInstruction))
				continue;
			TrimInstruction ti = (TrimInstruction) elem;
			if (!ti.left && !ti.right)
				result = true;
			if (!ti.right)
				continue;
			result = true;
			int firstLineIndex = firstNewLineIndex() + 1;
			if (firstLineIndex == 0)
				return false;
			if (text.length > firstLineIndex
					&& text[firstLineIndex - 1] == '\r'
					&& text[firstLineIndex] == '\n')
				firstLineIndex++;
			char trailingPart[] = substring(text, firstLineIndex);
			char openingPart[] = substring(text, 0, firstLineIndex);
			if (trim(openingPart).length == 0) {
				text = trailingPart;
				beginLine++;
				beginColumn = 1;
				continue;
			}
			int lastNonWS;
			for (lastNonWS = openingPart.length - 1; Character
					.isWhitespace(text[lastNonWS]); lastNonWS--)
				;
			char printablePart[] = substring(text, 0, lastNonWS + 1);
			if (trim(trailingPart).length == 0) {
				boolean trimTrailingPart = true;
				TemplateElement te = nextTerminalNode();
				do {
					if (te == null || te.beginLine != endLine)
						break;
					if (te.heedsOpeningWhitespace())
						trimTrailingPart = false;
					if ((te instanceof TrimInstruction)
							&& ((TrimInstruction) te).left) {
						trimTrailingPart = true;
						break;
					}
					te = te.nextTerminalNode();
				} while (true);
				if (trimTrailingPart)
					trailingPart = EMPTY_CHAR_ARRAY;
			}
			text = concat(printablePart, trailingPart);
		}

		return result;
	}

	private int firstNewLineIndex() {
		String content = new String(text);
		int newlineIndex1 = content.indexOf('\n');
		int newlineIndex2 = content.indexOf('\r');
		int result = newlineIndex1 < 0 ? newlineIndex2 : newlineIndex1;
		if (newlineIndex1 >= 0 && newlineIndex2 >= 0)
			result = Math.min(newlineIndex1, newlineIndex2);
		return result;
	}

	private int lastNewLineIndex() {
		String content = new String(text);
		return Math.max(content.lastIndexOf('\r'), content.lastIndexOf('\n'));
	}

	private int openingCharsToStrip() {
		int newlineIndex = firstNewLineIndex();
		if (newlineIndex == -1 && beginColumn != 1)
			return 0;
		newlineIndex++;
		if (text.length > newlineIndex && newlineIndex > 0
				&& text[newlineIndex - 1] == '\r' && text[newlineIndex] == '\n')
			newlineIndex++;
		if ((new String(text)).substring(0, newlineIndex).trim().length() > 0)
			return 0;
		for (TemplateElement elem = prevTerminalNode(); elem != null
				&& elem.endLine == beginLine; elem = elem.prevTerminalNode())
			if (elem.heedsOpeningWhitespace())
				return 0;

		return newlineIndex;
	}

	private int trailingCharsToStrip() {
		String content = new String(text);
		int lastNewlineIndex = lastNewLineIndex();
		if (lastNewlineIndex == -1 && beginColumn != 1)
			return 0;
		String substring = content.substring(lastNewlineIndex + 1);
		if (substring.trim().length() > 0)
			return 0;
		for (TemplateElement elem = nextTerminalNode(); elem != null
				&& elem.beginLine == endLine; elem = elem.nextTerminalNode())
			if (elem.heedsTrailingWhitespace())
				return 0;

		return substring.length();
	}

	boolean heedsTrailingWhitespace() {
		if (isIgnorable())
			return false;
		for (int i = 0; i < text.length; i++) {
			char c = text[i];
			if (c == '\n' || c == '\r')
				return false;
			if (!Character.isWhitespace(c))
				return true;
		}

		return true;
	}

	boolean heedsOpeningWhitespace() {
		if (isIgnorable())
			return false;
		for (int i = text.length - 1; i >= 0; i--) {
			char c = text[i];
			if (c == '\n' || c == '\r')
				return false;
			if (!Character.isWhitespace(c))
				return true;
		}

		return true;
	}

	boolean isIgnorable() {
		if (text == null || text.length == 0)
			return true;
		if (!isWhitespace()) {
			return false;
		} 
			boolean atTopLevel = true;
			TemplateElement prevSibling = previousSibling();
			TemplateElement nextSibling = nextSibling();
			return (prevSibling == null && atTopLevel || nonOutputtingType(prevSibling))
					&& (nextSibling == null && atTopLevel || nonOutputtingType(nextSibling));
		
	}

	private boolean nonOutputtingType(TemplateElement element) {
		return (element instanceof Macro) || (element instanceof Assignment)
				|| (element instanceof AssignmentInstruction)
				|| (element instanceof PropertySetting)
				|| (element instanceof LibraryLoad)
				|| (element instanceof Comment);
	}

	private static char[] substring(char c[], int from, int to) {
		char c2[] = new char[to - from];
		System.arraycopy(c, from, c2, 0, c2.length);
		return c2;
	}

	private static char[] substring(char c[], int from) {
		return substring(c, from, c.length);
	}

	private static char[] trim(char c[]) {
		if (c.length == 0)
			return c;
		else
			return (new String(c)).trim().toCharArray();
	}

	private static char[] concat(char c1[], char c2[]) {
		char c[] = new char[c1.length + c2.length];
		System.arraycopy(c1, 0, c, 0, c1.length);
		System.arraycopy(c2, 0, c, c1.length, c2.length);
		return c;
	}

	boolean isWhitespace() {
		return text == null || trim(text).length == 0;
	}

	private static final char EMPTY_CHAR_ARRAY[];
	static final TextBlock EMPTY_BLOCK;
	private char text[];
	private final boolean unparsed;

	static {
		EMPTY_CHAR_ARRAY = new char[0];
		EMPTY_BLOCK = new TextBlock(EMPTY_CHAR_ARRAY, false);
	}
}
